/**
 * 
 */
package jmine.tec.test.proxy;

import java.io.Serializable;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;

import jmine.tec.proxy.chain.ChainElement;
import jmine.tec.proxy.chain.InvocationChain;

/**
 * @author takeshi
 */
public abstract class AbstractMockObjectChainElement implements ChainElement, Serializable {
    private Map<String, Object> values = new HashMap<String, Object>();

    /**
     * @return the values
     */
    public final Map<String, Object> getValues() {
        return this.values;
    }

    /**
     * @param values the values to set
     */
    public final void setValues(final Map<String, Object> values) {
        this.values = values;
    }

    /**
     * @param chain the {@link InvocationChain}
     * @return Object to be returned from the invocation
     * @throws Throwable the t
     * @see br.com.maps.util.proxy.chain.ChainElement#aroundInvoke(br.com.maps.util.proxy.chain.InvocationChain)
     */
    public final Object aroundInvoke(InvocationChain chain) throws Throwable {
        Method method = chain.getInvokingMethod();
        Class<?> type = method.getReturnType();
        if (this.values.containsKey(method.getName())) {
            Object val = this.values.get(method.getName());
            if (MockObjectSupport.checkCompatible(type, val)) {
                return val;
            }
        }
        return this.unespecifiedMethod(chain);
    }

    /**
     * Hook for subclasses to react to methods whitch return value is not specified
     * 
     * @param chain the {@link InvocationChain}
     * @return Object
     * @throws Throwable t
     */
    protected abstract Object unespecifiedMethod(InvocationChain chain) throws Throwable;

}
